[FE201] webpack 讓你把各種資源包在一起(基本介紹篇)


Posted by s103071049 on 2021-07-07

webpack is a module bundler

從模組化開始談

module (模組/模塊)

當我完成某個功能,我要如何方便地分享給其他人 ? 最簡單的方式就是寫一個 FUNCT,把 FUNCT 給別人用。如果不只有一個 FUNCT,就包成一個檔案。

NODE.JS => require/ module.exports()

在 utils.js 寫 code,在 node.js 裡面會將 Utils 這個物件給輸出

// utils.js
const Utils = {
  first: function(str) {
    return str[0]
  },
  last: function(str) {
    return str[str.length-1]
  }
}
module.exports = Utils

使用者只要 require 進來,引入進來就可以用裡面的 method。

// index.js
const utils = require('./utils')

console.log(utils.first('abcde'))

基本上 module 很多都是以檔案為單位。接著透過某種方式將 module 對外輸出,接著其他人就可以將它引入進來使用。

瀏覽器 => 透過全域變數

瀏覽器沒有 require 的語法,所以之前使用 jQuery,都是直接 script 東西進來,接著就有全域變數 $ 或全域變數 jQuery 這個物件可以使用。

因為透過全域變數輸出 module,所以有了命名衝突的問題

如果我有兩個 library,一個叫 jQuery,一個叫 math(裡面 $ 表示整數),現在我同時引用這兩個 library,我就不曉得到底 $ 代表的是甚麼。

所以 jQuery 提供了 jQuery.noConflict()

因為瀏覽器沒有 require 所以也只能透過全域變數進行輸出,因此會有命名衝突的缺陷。node.js 就沒有,因為它 import 進來的名字可以自己改變。所以 node.js 這套 requrie 在 node.js 上面才可以用,在瀏覽器上面不行。

網頁上的 JS 與 node.js

js 是一個程式語言,在網頁上執行時它的執行環境(runtime)是瀏覽器,在電腦上用 node.js 執行時,它的執行環境就是 node.js。所以,在這兩個地方執行 js 是不同的兩件事情。

在 node.js 上執行有 require 可以用,在瀏覽器上執行沒有。

模組化規範各有不同

早期滿多人試著解決這個問題,因為在網頁上沒有模組機制非常麻煩。所以有些人自己實做了一些規範,CommonJS, AMD, UMD, 這些規範就像個家廠牌的手機充電線,它的功能目的都是一樣就是充電,但蘋果的頭與安卓的頭不同。它的目的都是一樣,但用法與規範不同,所以不同規範也可能不能相容。

它規範要用甚麼語法去使用一個模組,要怎麼將模組給別人用。 node.js 用的這套規範就叫做 CommonJS

上述的這幾個都不是官方的規範!

直到後來瀏覽器原生支援了 ES Modules 這個規範,可以用 import, export的語法。

舉例、

// utils.js
export function first(str) {
  return str[0]
}
// index.js
import {first} from './utils.js'
console.log(first('abc'))
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src= './index.js' type= 'module'></script>
</head>
<body>

</body>
</html>

這邊無法以檔案的方式打開,要用 server 開。

目前問題

  1. 支援度 : 這些規範比較新,在舊的瀏覽器上無法跑
  2. 技術相對早期階段 : 近幾年才出來,瀏覽器才支援,雖然已經有點成熟但還在相對早期階段。

結論

瀏覽器未支援的東西,用工具自己轉換就好了,所以有了這些工具,讓我們用模組化的規範,透過某個程式,幫忙 compile 之後產生出的檔案就可以丟到瀏覽器上執行。簡單地說,webpack 把我的模組全部都包在一起做一些轉換,我就可以在瀏覽器上使用這些東西。

把模組包在一起 === modules bundle

事實上,webpack 不只包模組,它將模組的概念推得更遠(將圖片、css 也當作模組),現階段,可以先理解成將 js 的模組包在一起讓他可以在瀏覽器上使用的一個工具。


環境設置

https://webpack.js.org/guides/getting-started/
npm init -y,再 npm install webpack webpack-cli --save-dev
開發專案,會使用各種不同工具,因此會安裝有不同的設定。會需要先 compile 過的 code 不會寫再根目錄,而是會寫在 src (source code) 底下,工具轉換完的 code 再放到其他地方。

所以,先開一個資料夾 src mkdir src

現在讓 index.js, utils.js 都放到 src 裡面。

const utils = require('./utils')

console.log(utils.first('abc'))
// utils.js
const Utils = {
  first: function(str) {
    return str[0]
  }
}

module.exports = Utils

確定 node index.js 在 node.js 上執行沒有問題

接著下指令 npx webpack 就會啟用 webpack 這個工具幫我們打包,webpack 預設的設定會去找 src 資料夾下 index.js 這個檔案,它會把這個當作程式的入口點(程式一開始就去執行這個檔案),打包好它會把東西放到 dist (distribution)。

因為之前設定過 minify, uglify 所以打包完的 main.js 會變成一個看不懂很醜的東西。打包好在執行一次 node dist/main.js 還是會出現相同的結果。

接著回到原本的 index.html,修改原本的 script => <script src= 'dist/main.js'></script>,打開檔案發現:我們寫的 require 的東西可以在瀏覽器上執行。

webpack 幫我們在瀏覽器上實作 require 這個功能,再幫我們把模組包在一起,所以我們才可以在瀏覽器上用這個東西。

利用關鍵字 js beautify => js beautify,可以將 dist/main.js 的 code 貼到上面,檢視其實作流程。

如果不是預設,可以做設定檔,touch webpack.config.js 如果不要預設檔名也可以改,改的話下 webpack 指令就要用不同的下法。

const path = require('path');

module.exports = {
  mode : '',
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

entry 表示程式的入口點,將模組引入進來做事情的地方就叫做 entry(入口點),通常都是 index.js,如果只有一個檔案通常那個檔案就會是 entry。

output 表示輸出的內容。其中 __dirname 會抓到現在執行的資料夾。所以 path: path.resolve(__dirname, 'dist'), 是說現在資料夾底下 dist 這個資料夾是我要輸出的路徑位置。

mode 沒有給預設為 production,production 表示正式環境/生產環境的版本,所以預設是 production,才會打包出已經壓縮過的 code。另外還有另一種是 mode: development,用這個模式打包出的 code 會比較看得懂,因為它不會幫我做壓縮。

先調整 package.json => 在 script 加入 "build" : "webpack",,所以現在我在 node.js 上打 npm run build,就會去執行 webpack 這個指令。接著 webpack 就會去找 webpack.config.js 這個檔案,然後根據這個設定檔進行打包。打包出來的檔案會把我要用的模組甚麼的都打包進去。

重點

  1. 安裝工具
  2. 找官方文件看怎麼執行
  3. 改設定檔

#Webpack







Related Posts

Linkedin Java 檢定題庫 子類別複寫

Linkedin Java 檢定題庫 子類別複寫

Day 137

Day 137

What is the concept of handle in Java?

What is the concept of handle in Java?


Comments